package org.kingtop.shiro.credentials;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.kingtop.cache.IRedisTemplate;

/**
 * <p>
 * User: chen jinbo
 * <p>
 * Date: 17-12-17
 * <p>
 * Version: 2.0
 * 用于验证用户名和密码是否匹配，自定义设置，如果超过5次用户名密码错误，锁定
 */
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {
	
	/**
	 * 重试次数的默认前缀
	 */
	public static final String RETRY_PREFIX = "RETRY_PREFIX";

	/**
	 * 默认锁定时间
	 */
	private static final int DEFAULT_RETRY_EXPIRE = 3600 * 24;

	private IRedisTemplate redisTemplate;

	/**
	 * 尝试次数的前缀
	 */
	private String retryPrefix = RETRY_PREFIX;

	/**
	 * 是否使用最大验证次数
	 */
	private boolean retryMaxEnable = true;

	/**
	 * 可以验证的次数
	 */
	private int retryMaxCount = 5;

	/**
	 * 锁定时间
	 */
	private int retryExpire = DEFAULT_RETRY_EXPIRE;

	public RetryLimitHashedCredentialsMatcher() {
	}

	/**
	 * 匹配用户输入的token的凭证（未加密）与系统提供的凭证（已加密）
	 * */
	@Override
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		String username = (String) token.getPrincipal();
		if (retryMaxEnable) {
			Long retryCount = redisTemplate.incr(retryPrefix + username);
			redisTemplate.expire(retryPrefix + username, retryExpire);
			if (retryCount > retryMaxCount) {
				// if retry count > 5 throw
				throw new ExcessiveAttemptsException();
			}
		}

		if(token == null || info == null){
			return false;
		}
		// 调用基类方法验证用户名和密码
		boolean matches = super.doCredentialsMatch(token, info);
		if (matches) {
			// clear retry count
			redisTemplate.del(retryPrefix + username);
		}
		return matches;
	}

	public boolean isRetryMaxEnable() {
		return retryMaxEnable;
	}

	public void setRetryMaxEnable(boolean retryMaxEnable) {
		this.retryMaxEnable = retryMaxEnable;
	}

	public int getRetryMaxCount() {
		return retryMaxCount;
	}

	public void setRetryMaxCount(int retryMaxCount) {
		this.retryMaxCount = retryMaxCount;
	}

	/**
	 * @return the redisTemplate
	 */
	public IRedisTemplate getRedisTemplate() {
		return redisTemplate;
	}

	/**
	 * @param redisTemplate the redisTemplate to set
	 */
	public void setRedisTemplate(IRedisTemplate redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	public String getRetryPrefix() {
		return retryPrefix;
	}

	public void setRetryPrefix(String retryPrefix) {
		this.retryPrefix = retryPrefix;
	}

	public int getRetryExpire() {
		return retryExpire;
	}

	public void setRetryExpire(int retryExpire) {
		this.retryExpire = retryExpire;
	}
	
}
